/*
 * IndividualUtils.cpp
 *
 *  Created on: 15-01-2011
 *      Author: Piotr
 */

#include "utils/IndividualUtils.hpp"
#include "geometry/Line.hpp"
#include "utils/VectorUtils.hpp"
#include "world/visitors/BlockingElementsGetterVisitor.hpp"
#include "world/visitors/BarriersGetterVisitor.hpp"

void IndividualUtils::removeUnvisibleElements(const Vector& position,
		World::ElementsVector& elements)
{

	BlockingElementsGetterVisitor getter;
	getter.visitEveryElement(elements);
	vector<Element*> barriers = getter.getVector();

	vector<Element*> toDeletes;
	for(vector<Element*>::iterator it = barriers.begin(); it != barriers.end(); ++it)
	{
		Line line = Line(position, (*it)->getBounds().getCenter());
		for(vector<Element*>::iterator itInner = it + 1; itInner != barriers.end(); ++itInner)
		{
			Line toElement = Line(position, (*itInner)->getBounds().getCenter());
			if((*itInner)->getBounds().intersects(line) || (*it)->getBounds().intersects(toElement))
			{
				if(toElement.getSquaredLength() > line.getSquaredLength() && VectorUtils::find<Element*>(
						toDeletes, *itInner) == toDeletes.end())
				{
					toDeletes.push_back(*itInner);
				}
				else if(toElement.getSquaredLength() < line.getSquaredLength() && VectorUtils::find<
						Element*>(toDeletes, *it) == toDeletes.end())
				{
					toDeletes.push_back(*it);
				}
			}
		}
	}

	BOOST_FOREACH(Element* toDelete, toDeletes)
				{
					vector<Element*>::iterator it = VectorUtils::find<Element*>(barriers, toDelete);
					if(it != barriers.end())
					{
						barriers.erase(it);
					}
				}

	World::ElementsVector toDeletesAfterBarriers;
	for(World::ElementsVector::iterator it = elements.begin(); it != elements.end(); ++it)
	{
		Line line = Line(position, (*it)->getBounds().getCenter());
		for(vector<Element*>::iterator itInner = barriers.begin(); itInner != barriers.end(); ++itInner)
		{
			Line toElement = Line(position, (*itInner)->getBounds().getCenter());
			if((*itInner)->getBounds().intersects(line) && toElement.getSquaredLength()
					< line.getSquaredLength() && VectorUtils::find<boost::shared_ptr<Element> >(
					toDeletesAfterBarriers, *it) == toDeletesAfterBarriers.end())
			{
				toDeletesAfterBarriers.push_back(*it);
			}
		}
	}

	BOOST_FOREACH(boost::shared_ptr<Element>& toDelete, toDeletesAfterBarriers)
				{
					World::ElementsVector::iterator it = VectorUtils::find<boost::shared_ptr<Element> >(
							elements, toDelete);
					if(it != elements.end())
					{
						elements.erase(it);
					}
				}
}

bool IndividualUtils::intersectsAnyBarrier(const geometry::Rectangle& bounds,
		World::ElementsVector& elements)
{
	BarriersGetterVisitor getter;
	getter.visitEveryElement(elements);
	vector<Barrier*> barriers = getter.getVector();

	for(vector<Barrier*>::iterator it = barriers.begin(); it != barriers.end(); ++it)
	{
		if(bounds.intersects((*it)->getBounds()))
		{
			return true;
		}
	}
	return false;
}
